
import { getOnlyKey } from '../utils';
import { EventBusModel, DsEventBusPlugin, CbFnType, EventBusValueModel } from '../interface';


export * from '../utils';
export * from '../interface';

export class DsEventBus<T extends string | number>{

    private eventBus: EventBusModel<T> = {};
    constructor() {

    }

    private setEmpty(name: T) {
        if (!this.eventBus[name]) {
            this.eventBus[name] = { lastArg: [], fns: [] };
        }
    }

    pipe(...args: any[]) {
        const plugs: DsEventBusPlugin[] = [];
        if (args) {
            args.forEach(plug => {
                plugs.push(plug);
            })
        }
        return {
            on: (name: T, cb: CbFnType, option?: { immediately: boolean }) => {
                return this.pluginOn(name, cb, option, plugs);
            }
        };
    }

    private pluginOn(name: T, cb: CbFnType, option?: { immediately: boolean }, plugs?: DsEventBusPlugin[]): string {
        const key = getOnlyKey('EventBus');
        this.setEmpty(name);
        this.eventBus[name]?.fns.push({ key, cb, plugs: plugs });
        if(option && option.immediately) {
            cb.apply(null, this.eventBus[name]?.lastArg ?? [])
        }
        return key
    }

    on(name: T, cb: CbFnType, option?: { immediately: boolean }): string {
       return this.pluginOn(name, cb, option, []);
    }

    private exturePlugin(plugs: DsEventBusPlugin[], index: number, next: () => void) {
        if (index < plugs.length) {
            plugs[index](() => {
                this.exturePlugin(plugs, index + 1, next)
            })
        } else {
            next()
        }
    }

    emit(name: T, ...arg: any[]) {
        this.setEmpty(name);
        (this.eventBus[name] as EventBusValueModel).lastArg = arg;
        if (!this.eventBus[name] || !this.eventBus[name]?.fns.length) {
            return;
        }
        this.eventBus[name]?.fns.forEach(v => {
            if (v.plugs) {
                this.exturePlugin(v.plugs, 0, () => {
                    v.cb.apply(this.emit, arg)
                })
            } else {
                v.cb.apply(this.emit, arg)
            }
        })
    }


    remove(name: T, key: string) {
        if (!this.eventBus[name] || !this.eventBus[name]?.fns.length) {
            console.warn(`移除${key}程序，没有程序正在监听${name}事件`);
            return;
        }
        const index = (this.eventBus[name] as EventBusValueModel).fns.findIndex(v => v.key === key);
        console.log((this.eventBus[name] as EventBusValueModel).fns.length);
        if (index < 0) {
            console.warn(`监听的程序${key}不存在`);
        } else {
            (this.eventBus[name] as EventBusValueModel).fns.splice(index, 1);
        }
    }

    /**
     * 清除所有事件监听
     * @param name T
     */
    removeAll(name?: T) {
        if (name) {
            this.eventBus[name] = { lastArg: [], fns: [] };
        } else {
            this.eventBus = {};
        }
    }

}



export default {
    DsEventBus
}